﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Dispatcher;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Configuration;

namespace SmartWCFWrapper.Server
{
    /*
    This class will allow the server to determine:  (http://blogs.msdn.com/b/pedram/archive/2008/01/25/wcf-error-handling-and-some-best-practices.aspx)
     * 
-          Decide to send a fault to the client or not,
-          Replace an exception with a fault,
-          Replace a fault with another fault,
-          Perform logging,
-          Perform other custom activities
     */
    // Add fault logging on the server side: http://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.ierrorhandler.aspx#Y849

    [DataContract]
    public class GreetingFault
    {
        string errorMessage;

        public GreetingFault(string msg)
        {
            errorMessage = msg;
        }
    }

    public class GreetingErrorHandler : IErrorHandler
    {
        /// <summary>
        /// The IErrorHandler.HandleError method on the other hand is usually used to implement error-related behaviours such as error logging, system notifications, shutting down the application, and so on. This would be my recommended place to add logging capabilities.
        /// 
        /// IErrorHandler.HandleError can be called at multiple places inside the service, and depending on where the error is thrown, the HandleError method may or may not be called by the same thread as the operation. In other words, WCF does not make any guarantees on which thread the HandleError call may be processed.
        /// </summary>
        /// <param name="error"></param>
        /// <returns></returns>
        public bool HandleError(Exception error)
        {
            // Returning true indicates you performed your behavior.
            return true;
        }

        // One area that you could perhaps use this approach is when you want to create a central place for converting exceptions to faults before they are sent to the client (ensuring that the instance is not disposed and the channel is not moved to the Faulted state)
        // This is a trivial implementation that converts Exception to FaultException<GreetingFault>.
        public void ProvideFault(Exception error, MessageVersion ver, ref Message fault)
        {
            FaultException<GreetingFault> faultException = new FaultException<GreetingFault>(new GreetingFault(error.Message), "This fault was created by ProvideFault");
            MessageFault messageFault = faultException.CreateMessageFault();
            fault = Message.CreateMessage(ver, messageFault, faultException.Action);
        }
    }
     /*
      Instructions Part1: Use this class to add the behavior by code.  Use the ExtensionElement below to add by config.
      */
    public class GreetingFaultBehavior : IServiceBehavior
    {
        public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
            IErrorHandler errorHandler;

            errorHandler = new GreetingErrorHandler();

            foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
            {
                ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;
                channelDispatcher.ErrorHandlers.Add(errorHandler);
            }
        }

        public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
        {
        }
    }
    /*
     * 
     * Instructions:
     * 
     * The following code example shows how to configure the GreetingFaultBehavior using the 
     * GreetingFaultBehaviorExtensionElement. Notice that the extension element must be registered 
     * within the <extensions> element
     * 
     <system.serviceModel>
  <behaviors>
    <serviceBehaviors>
      <behavior>
        <serviceMetadata httpGetEnabled="true"/>
        <serviceDebug includeExceptionDetailInFaults="false"/>
        <!-- Add the greetingFaultBehavior --------------------------------------->
        <greetingFaultBehavior />
      </behavior>
    </serviceBehaviors>
  </behaviors>
  <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  <!-- Register the class that implements the configuration element --------------->
  <extensions>
    <behaviorExtensions>
      <add
        name="greetingFaultBehavior"
        type="GreetingService.GreetingFaultBehaviorExtensionElement, GreetingService, Version=1.0.0.0, Culture=neutral"
      />
    </behaviorExtensions>
  </extensions>
</system.serviceModel>
     
     
     
     */
    public class GreetingFaultBehaviorExtensionElement : BehaviorExtensionElement
    {
        public override Type BehaviorType
        {
            get { return typeof(GreetingFaultBehavior); }
        }

        protected override object CreateBehavior()
        {
            return new GreetingFaultBehavior();
        }
    }

}
